package com.zengchen.content.config.ribbonrule;

import com.alibaba.nacos.api.exception.NacosException;
import com.alibaba.nacos.api.naming.NamingService;
import com.alibaba.nacos.api.naming.pojo.Instance;
import com.netflix.client.config.IClientConfig;
import com.netflix.loadbalancer.AbstractLoadBalancerRule;
import com.netflix.loadbalancer.DynamicServerListLoadBalancer;
import com.netflix.loadbalancer.Server;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cloud.alibaba.nacos.NacosDiscoveryProperties;
import org.springframework.cloud.alibaba.nacos.ribbon.NacosServer;
import org.springframework.util.CollectionUtils;

import java.util.List;
import java.util.Objects;
import java.util.stream.Collectors;

/**
 * <p>
 * 同集群权重负载规则
 * </p>
 *
 * @author zengchen
 * @since 2019-08-11
 */
@Slf4j
public class NacosSameClusterWeightedRule extends AbstractLoadBalancerRule {

    @Autowired
    private NacosDiscoveryProperties discoveryProperties;

    private Server choose(DynamicServerListLoadBalancer lb, Object key) {
        if (lb == null) {
            return null;
        }
        try {
            // 本服务所属集群
            String clusterName = discoveryProperties.getClusterName();
            // 要请求的服务的名称
            String targetInstanceName = lb.getName();
            // 服务相关Api
            NamingService namingService = discoveryProperties.namingServiceInstance();
            // 获取目标服务所有实例(健康的实例)
            List<Instance> instances = namingService.selectInstances(targetInstanceName, true);
            // 获得同集群实例
            List<Instance> sameClusterInstances = instances.stream()
                    .filter(instance -> {
                        return Objects.equals(instance.getClusterName(), clusterName);
                    }).collect(Collectors.toList());
            // 等待被选择的实例
            List<Instance> toBeChosenInstances = sameClusterInstances;
            // 如果没有同集群的实例，那就用所有实例
            if(CollectionUtils.isEmpty(sameClusterInstances)){
                toBeChosenInstances = instances;
                log.warn("发生跨集群调用，集群名称={},目标服务名称={}",clusterName,targetInstanceName);
            }
            // 根据权重从toBeChosenInstances选择一个实例
            return new NacosServer(ExtendsBalancer.getInstanceByWeight(toBeChosenInstances));
        } catch (NacosException e) {
            log.error("同集群负载规则发生异常", e);
        }
        return null;
    }

    @Override
    public Server choose(Object key) {
        log.info("负载均衡规则：NacosSameClusterWeightedRule");
        return choose((DynamicServerListLoadBalancer) getLoadBalancer(), key);
    }

    @Override
    public void initWithNiwsConfig(IClientConfig iClientConfig) {

    }
}

